package soar.test.json.jackson;

import java.io.ByteArrayOutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
//import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class App
{
    public static void main(String args[])
    {
        new App().run();
    }

    private void run()
    {
        try
        {
            String split = "==================================================";
            System.out.println(split);

            generate();
            System.out.println(split);

            parse();
            System.out.println(split);

            // 多态
            new Polymorphic().run();
            System.out.println(split);
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
    }

    private String input_s;

    private void generate() throws Exception
    {
        System.out.println("流组装");
        System.out.println();

        JsonFactory factory = new JsonFactory();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        JsonGenerator generator = factory.createGenerator(out,
                JsonEncoding.UTF8);
        generator.useDefaultPrettyPrinter();
        generator.writeStartObject(); // {
        generator.writeObjectFieldStart("name"); // name:{
        generator.writeStringField("first", "Joe");
        generator.writeStringField("last", "Sixpack");
        generator.writeEndObject(); // }
        generator.writeArrayFieldStart("locations"); // locations:[
        generator.writeString("上海");
        generator.writeString("北京");
        generator.writeEndArray(); // ]
        generator.writeStringField("gender", "M");
        generator.writeBooleanField("verified", true);
        generator.writeNumberField("age", 40);
        generator.writeFieldName("image");
        byte[] img = "一江春水向东流".getBytes();
        generator.writeBinary(img);
        generator.writeEndObject(); // }
        generator.close();
        System.out.println(out.toString());

        System.out.println("------------------------------------------");

        System.out.println("对象转换");
        System.out.println();

        ObjectMapper mapper;
        String out_s;

        Map<String, String> map = new HashMap<>();
        map.put("姓名", "甲");
        map.put("地址", "上海");
        map.put("爱好", "电影");
        mapper = new ObjectMapper();
        out_s = mapper.writeValueAsString(map);
        System.out.println(out_s);

        System.out.println();

        List<SimpleUser> list = new ArrayList<>();
        SimpleUser su = new SimpleUser();
        su.id = 100;
        su.name = "甲";
        su.list = Arrays.asList(1, 2, 3, 4, 5);
        list.add(su);
        su = new SimpleUser();
        su.id = 200;
        su.name = "乙";
        su.list = Arrays.asList("a", "b", "c");
        list.add(su);
        su = new SimpleUser();
        su.id = 300;
        su.name = "{\"name\":\"丙\"}";
        System.out.println(String.format("su.name: %s", su.name));
        su.list = Arrays.asList(new Address(1, "上海"), new Address(2, "北京"));
        list.add(su);
        mapper = new ObjectMapper();
        out_s = mapper.writeValueAsString(list);
        System.out.println(out_s);

        System.out.println();

        User user = new User();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        user.id = 1;
        user.name = "阿隆";
        user.salary.put("月薪", 10000);
        user.salary.put("绩效", 2000);
        User.Account account = user.new Account();
        account.setBalance(1000);
        user.account = account;
        user.logs.add(new Log(1, format.parse("2010-01-01 09:30:00"), "入职"));
        user.logs.add(new Log(2, format.parse("2012-05-01 14:00:00"), "升职经理"));
        mapper = new ObjectMapper();
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        mapper.setDateFormat(format);
        out_s = mapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(user);
        System.out.println(out_s);
        Object o = user;
        out_s = mapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(user);
        System.out.println(out_s);
        input_s = out_s;
    }

    private void parse() throws Exception
    {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        System.out.println("树模式");
        System.out.println();

        User user = new User();

        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readTree(input_s);
        user.id = root.path("id").intValue();
        user.name = root.path("name").textValue();
        JsonNode salary = root.path("salary");
        Iterator<Map.Entry<String, JsonNode>> it = salary.fields();
        while (it.hasNext())
        {
            Map.Entry<String, JsonNode> entry = it.next();
            String k = entry.getKey().trim();
            int v = entry.getValue().intValue();
            user.salary.put(k, v);
        }
        JsonNode logs = root.path("logs");
        for (int i = 0; i < logs.size(); i++)
        {
            int id = logs.get(i).path("id").intValue();
            Date time = format.parse(logs.get(i).path("time").textValue());
            String content = logs.get(i).path("content").textValue().trim();
            user.logs.add(new Log(id, time, content));
        }

        System.out.println("unknown(int): " + root.path("unknown").intValue());
        System.out
                .println("unknown(text): " + root.path("unknown").textValue());
        System.out.println("id: " + user.id);
        System.out.println("name: " + user.name);
        System.out.println("salary:");
        // for (Map.Entry<String, Integer> entry : user.salary.entrySet())
        // {
        // System.out.println(" " + entry.getKey() + " --> "
        // + entry.getValue());
        // }
        user.salary.forEach(
                (k, v) -> System.out.println("    " + k + " --> " + v));
        System.out.println("logs:");
        user.logs.forEach((v) -> System.out.println("    " + " id:" + v.id
                + " time:" + format.format(v.time) + " content:" + v.content));

        System.out.println("------------------------------------------");

        System.out.println("数据绑定模式");
        System.out.println();

        mapper = new ObjectMapper();
        mapper.setDateFormat(format);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
                false);

        System.out.println("Map");
        String map_s = "{\"甲\" : 100,\"乙\" : 200,\"丙\" : 300}";
        // @SuppressWarnings("unchecked")
        // Map<String, Integer> map = mapper.readValue(map_s, Map.class);
        Map<String, Integer> map = mapper.readValue(map_s,
                new TypeReference<Map<String, Integer>>()
                {
                });
        map.forEach((k, v) -> {
            System.out.println(k + " : " + v);
        });
        System.out.println();

        System.out.println("简单类");
        String simple_input_s = "{\"id\" : 1,\"name\" : \"阿隆\",\"age\" : 40, \"list\":[1,2,3]}";
        SimpleUser su = mapper.readValue(simple_input_s, SimpleUser.class);
        System.out.println("" + simple_input_s);
        System.out.println("id: " + su.id);
        System.out.println("name: " + su.name);
        System.out.println("list: " + su.list);
        simple_input_s = "{\"id\" : null,\"name\" : null,\"age\" : 40, \"list\": [\"a\",\"b\",\"c\"]}";
        // 自定义类不能识别
        // simple_input_s = "{\"id\" : null,\"name\" : null,\"age\" : 40,
        // \"list\": [{\"id\":1,\"text\":\"上海\"}]}";
        System.out.println("" + simple_input_s);
        su = mapper.readValue(simple_input_s, SimpleUser.class);
        System.out.println("id: " + su.id);
        System.out.println("name: " + su.name);
        System.out.println("list: " + su.list);
        // System.out.println("list: " + su.list.stream().map(x -> {
        // Address a = (Address) x;
        // return a.id + "|" + a.text;
        // }).collect(Collectors.joining(", ")));
        System.out.println();

        System.out.println("复杂类");
        user = mapper.readValue(input_s, User.class);
        System.out.println("id: " + user.id);
        System.out.println("name: " + user.name);
        System.out.println("salary:");
        System.out.println("account: " + user.account.getBalance());
        user.salary.forEach(
                (k, v) -> System.out.println("    " + k + " --> " + v));
        System.out.println("logs:");
        user.logs.forEach((e) -> System.out.println("    " + " id:" + e.id
                + " time:" + format.format(e.time) + " content:" + e.content));
    }
}

// 必须外部类定义

class Address
{
    public int id;
    public String text;

    public Address()
    {

    }

    public Address(int id, String text)
    {
        this.id = id;
        this.text = text;
    }
}

class SimpleUser
{
    public int id = 0;
    @JsonRawValue
    public String name = "";
    public List<?> list; // 可以生成，不能解析
}

// @JsonIgnoreProperties(ignoreUnknown = true)
class User
{
    public int id;

    @JsonProperty("name")
    public String name;

    // 内部类
    public class Account
    {
        private long balance;

        public long getBalance()
        {
            return balance;
        }

        public void setBalance(long balance)
        {
            this.balance = balance;
        }

    }

    // 可以直接使用内部类
    public Account account;

    public Map<String, Integer> salary = new HashMap<>();

    // 引用链中用到的类不能在内部定义
    public List<Log> logs = new ArrayList<>();

    // "unused" : null
    // null不转换
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public Object unused1 = null;

    // "unused" : { }
    // 默认空出错，需要mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,
    // false);
    // 空或null不转换
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    public Object unused2 = new Object();
}

class Log
{
    public int id;
    public Date time;
    public String content;

    // 如定制构造方法，必须提供缺省构造方法
    public Log()
    {

    }

    public Log(int id, Date time, String content)
    {
        this.id = id;
        this.time = time;
        this.content = content;
    }
}
